package com.common.pattern.pipeline.config;

import com.common.pattern.pipeline.bo.BusinessContext;
import com.common.pattern.pipeline.bo.PipelineContext;
import com.common.pattern.pipeline.handler.impl.ContextExpirationDateHandler;
import com.common.pattern.pipeline.handler.impl.ContextFactoryHandler;
import com.common.pattern.pipeline.handler.impl.ContextProductionHandler;
import com.common.pattern.pipeline.handler.impl.ContextQualityHandler;
import com.common.pattern.pipeline.utils.SpringUtil;
import com.common.pattern.pipeline.handler.ContextHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


/**
 * @Author: xuxiang
 * @Date: 2023-8-10
 * @Description: 管道每一节管子的路由顺序配置
 */
//@Configuration  由调用者自己决定管道顺序
@ConditionalOnClass(ContextHandler.class)
@Slf4j
public class PipelineRouteConfig {

    @Resource
    private PipelineManualProperty pipelineManualProperty;

    protected static final
    Map<Class<? extends PipelineContext>,
            List<Class<? extends ContextHandler<? extends PipelineContext>>>> PIPELINE_ROUTE_MAP = new HashMap<>(4);

    static {
        PIPELINE_ROUTE_MAP.put(BusinessContext.class,
                Arrays.asList(
                        ContextFactoryHandler.class,
                        ContextProductionHandler.class,
                        ContextExpirationDateHandler.class,
                        ContextQualityHandler.class
                ));
    }

    /**
     * 在 Spring 启动时，根据路由表生成对应的管道映射关系，
     * PipelineExecutor 从这里获取处理器列表
     */
    @Bean("pipelineRouteMap")
    @SuppressWarnings("all")
    public Map<Class<? extends PipelineContext>, List<? extends ContextHandler<? extends PipelineContext>>> getHandlerPipelineMap() {

        Map<String, List<String>> pipelineMap = pipelineManualProperty.getPipelineMap();
        if (!CollectionUtils.isEmpty(pipelineMap)) {

            Map<Class<? extends PipelineContext>, List<? extends ContextHandler<? extends PipelineContext>>> beanMap =
                    new HashMap<>(pipelineMap.size());

            pipelineMap.forEach((context, pipelineList) -> {
                try {
                    Class contextClazz = Class.forName(context);
                    List<ContextHandler<? extends PipelineContext>> handlerList = new ArrayList<>(pipelineList.size());
                    Map<String, ContextHandler> beansOfType = SpringUtil.getBeansOfType(ContextHandler.class);

                    // 防止多次配置bean
                    pipelineList = pipelineList.stream().distinct().collect(Collectors.toList());

                    for (String handlerClassName : pipelineList) {
                        ContextHandler<? extends PipelineContext> contextHandler = beansOfType.get(handlerClassName);
                        Assert.notNull(contextHandler, "pipelineList bean {" + handlerClassName + "} not exist!");
                        handlerList.add(contextHandler);
                    }

                    beanMap.put(contextClazz, handlerList);
                } catch (ClassNotFoundException e) {
                    log.error("配置bean class不存在", ExceptionUtils.getStackTrace(e));
                    throw new RuntimeException(e);
                } catch (Exception e) {
                    log.error("自定义管道class错误,原因:{}", ExceptionUtils.getStackTrace(e));
                    throw new RuntimeException(e);
                }
            });
            return beanMap;
        }

        return this.initDefaultBean();
    }

    /**
     * 默认加载管道的业务类型顺序
     */
    private Map<Class<? extends PipelineContext>, List<? extends ContextHandler<? extends PipelineContext>>> initDefaultBean() {
        PIPELINE_ROUTE_MAP.put(BusinessContext.class,
                Arrays.asList(
                        ContextFactoryHandler.class,
                        ContextProductionHandler.class,
                        ContextExpirationDateHandler.class,
                        ContextQualityHandler.class
                ));

        return PIPELINE_ROUTE_MAP.entrySet()
                .stream()
                .collect(
                        Collectors.toMap(
                                Map.Entry::getKey,
                                entry -> entry.getValue()
                                        .stream()
                                        .map(SpringUtil::getBean)
                                        .collect(Collectors.toList())
                        )
                );
    }

    /**
     * 根据给定的管道中 ContextHandler 的类型的列表，构建管道
     */
    private List<? extends ContextHandler<? extends PipelineContext>> toPipeline(
            Map.Entry<Class<? extends PipelineContext>, List<Class<? extends ContextHandler<? extends PipelineContext>>>> entry) {
        return entry.getValue()
                .stream()
                .map(SpringUtil::getBean)
                .collect(Collectors.toList());
    }

}